package com.nulldev.util.threading.v4_core;

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.other.arrays.QueuedList;
import com.nulldev.util.threading.v3_extensions.Task;

/**
 * The DATE executor, designed for high performance and low performance tasks. <br>
 * 
 * Designed to use queues and support various performance levels. (High, Medium+Low, Low) <br>
 * 
 * Design: 
 * Use a queued list that supports high perfomance I/O to feed <code>n</code> (default: 8) executors that take tasks at their own rate. <br>
 * TODO: Add support for ATCA (Adaptive Task Count Adaption, dynamically interchange with other executors if the primary executor queue is FULL.)
 * @author null
 * @since 2.7
 * @warning This a strict work in progress.
 */
@Deprecated
public class DynamicAllocatedThreadExecutor implements Closeable {
	
	public static enum DATETaskType {
		REAL_TIME_EXECUTION,
		LOW_PRIORITY_QUEUE,
		LEGACY_QUEUE
	}
	
	@SuppressWarnings("rawtypes")
	private final List<Task> tasks;
	private final LinkedList<Executor> executors;

	protected static class Executor extends Thread {
		private static final Logger logger = LoggerFactory.getLogger(true, true);
		
		private final DynamicAllocatedThreadExecutor source;
		@SuppressWarnings({"rawtypes"})
		private volatile Task task;
		private boolean running;
		
		public Executor(final DynamicAllocatedThreadExecutor source) {
			super("DATE Executor: High Priority Executor");
			this.source = source;
			this.start();
		}
		
		private int lagBack = 1;
		
		@SuppressWarnings("rawtypes")
		@Override
		public void run() {
			while (true) {
				if (!this.source.hasTask()) {
					try {
						Thread.sleep(20L * lagBack);
						if (this.lagBack > 6) {
							this.lagBack = 1;
						}else {
							this.lagBack += 1;
						}
					}catch (Exception e) {}
					continue;
				}else {
					try {
						if (!this.source.hasTask()) {
							continue;
						}
						final Task task = this.source.request();
						if (task.completed()) {
							continue;
						}
						this.task = task;
						this.running = true;
						task._run();
						this.running = false;
					}catch (Throwable t) {
						logger.error("Running task failed.", t);
						this.running = false;
					}
					try {
						Thread.sleep(10L);
					}catch (Exception e) {}
				}
				
			}
		}
		
		public boolean isBusy() {
			return running;
		}
		
		@SuppressWarnings("rawtypes")
		public Task getTask() {
			return this.task;
		}
	}
	
	public DynamicAllocatedThreadExecutor() {
		this(8);
	}
	
	public boolean hasTask() {
		return !this.tasks.isEmpty();
	}

	@SuppressWarnings("rawtypes")
	public DynamicAllocatedThreadExecutor(final int highPriorityThreads) {
		this.tasks = new LinkedList<Task>();
		this.executors = new LinkedList<Executor>();
		for (int i = 0; i < highPriorityThreads; i++) {
			this.executors.add(new Executor(this));
		}
	}
	
	@SuppressWarnings("rawtypes")
	protected Task request() {
		return this.tasks.remove(0);
	}
	
	public boolean submit(@SuppressWarnings("rawtypes") final Task task, final DATETaskType type) {
		if (type.equals(DATETaskType.REAL_TIME_EXECUTION)) {
			return this.tasks.add(task);
		}
		return false;
	}

	@Override
	public void close() throws IOException {
	}
}
